#动态类型与 PSObject
#简介
PowerShell 中的每个对象都会被包装成 PSObject。这层包装让原本的 .NET 对象可以临时附加属性、方法和类型名,而不需要修改原始类型。理解 PSObject 是掌握动态对象、自定义输出和 ETS 的关键。
#PSObject
创建对象后,可以通过 PSObject 属性查看它的成员和类型信息:
$obj = [pscustomobject]@{ Name = 'demo' }
$obj.PSObject.Properties
$obj.PSObject.Methods
$obj.PSObject.Properties['Name'].Value
$obj.PSObject.Properties 返回属性集合,每个元素包含 Name、MemberType、Value 等信息。
#pstypenames
每个对象都有一条类型名链,PowerShell 用它查找类型数据:
$obj = [pscustomobject]@{ Name = 'demo' }
$obj.pstypenames
输出依次为 System.Management.Automation.PSCustomObject 和 System.Object。也可以使用 $obj.PSObject.TypeNames,两者指向同一份类型名集合。向链首插入自定义类型名后,可以针对该类型名配置成员和格式化:
$obj.PSObject.TypeNames.Insert(0, 'My.App.Demo')
#Add-Member
Add-Member 用于向对象实例动态添加成员。默认不输出结果,需要返回对象时使用 -PassThru:
$obj = [pscustomobject]@{ Name = 'demo' }
$obj | Add-Member -MemberType NoteProperty -Name Version -Value '1.0'
$obj | Add-Member -MemberType ScriptProperty -Name Label -Value {
"$($this.Name) v$($this.Version)"
}
$obj | Add-Member -MemberType ScriptMethod -Name Describe -Value {
"$($this.Name) version $($this.Version)"
}
$obj.Version
$obj.Label
$obj.Describe()
输出依次为 1.0、demo v1.0 和 demo version 1.0。
NoteProperty 保存静态值;ScriptProperty 和 ScriptMethod 在每次访问时执行脚本块,其中的 $this 指向当前对象。CodeMethod 则绑定 .NET 静态方法,适合高性能场景。
#属性赋值语法
对于 PSCustomObject,可以直接给不存在的属性赋值,PowerShell 会自动添加 NoteProperty:
$obj = [pscustomobject]@{ Name = 'demo' }
$obj.Enabled = $true
$obj.Enabled
True
这种语法只适用于可以扩展的对象;对多数普通 .NET 对象直接赋值不存在的属性会报错。
#动态成员与类型数据
Add-Member 只影响当前对象实例。如果希望某个类型的所有对象都拥有同样的成员,应使用 Update-TypeData:
Update-TypeData -TypeName 'My.App.Demo' `
-MemberType ScriptProperty `
-MemberName Display `
-Value { "$($this.Name)!" } `
-Force
更多内容参见 Get-Member 帮助手册。
#注意事项
- 动态成员默认只存在于当前会话和当前对象实例中。
ScriptProperty每次读取都会执行脚本块,避免在其中进行耗时操作。- 类型名和动态成员是元数据,不构成安全边界。
- 对共享对象添加成员时,其他代码也可能看到这些改动。